package com.hxzy.module.admin.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.hxzy.framework.common.constant.AuthConstant;
import com.hxzy.framework.common.constant.RedisConstant;
import com.hxzy.framework.common.exception.ApiException;
import com.hxzy.framework.common.resp.ResultCode;
import com.hxzy.framework.web.util.WebFrameworkUtils;
import com.hxzy.module.admin.api.account.req.AdminAccountResp;
import com.hxzy.module.admin.api.menu.resp.ModuleAuthorityResp;
import com.hxzy.module.admin.api.role.req.*;
import com.hxzy.module.admin.api.role.resp.AdminRoleResp;
import com.hxzy.module.admin.api.role.resp.RoleAuthorityTreeResp;
import com.hxzy.module.admin.entity.AdminAccountInnerRole;
import com.hxzy.module.admin.entity.AdminRole;
import com.hxzy.module.admin.entity.AdminRoleInnerModule;
import com.hxzy.module.admin.mapstruct.AdminMapStruct;
import com.hxzy.module.admin.service.*;
import com.hxzy.module.admin.mapper.AdminRoleMapper;
import io.seata.spring.annotation.GlobalTransactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

/**
* @author 11452
* @description 针对表【admin_role(总部角色表)】的数据库操作Service实现
* @createDate 2024-01-28 10:57:28
*/
@Service
public class AdminRoleServiceImpl extends ServiceImpl<AdminRoleMapper, AdminRole>
    implements AdminRoleService{

    @Autowired
    private AdminMenuService adminMenuService;

    /**
     * 角色关联的模块权限表
     */
    @Autowired
    private AdminRoleInnerModuleService adminRoleInnerModuleService;

    /**
     * 角色关联的账号信息表
     */
    @Autowired
    private AdminAccountInnerRoleService adminAccountInnerRoleService;

    /**
     * 角色对应的账户信息表
     */
    @Autowired
    private AdminAccountService adminAccountService;

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 角色列表
     * @param req
     * @return
     */
    @Override
    public PageInfo<AdminRoleResp> roleList(AdminRoleReq req) {
        return PageHelper
                .startPage(req.getPageNum(), req.getPageSize())
                .doSelectPageInfo(() -> this.baseMapper.findRoleListRespByCondition(req, WebFrameworkUtils.getMerchantId()));
    }

    /**
     * 角色权限树
     * @param roleId
     * @return
     */
    @Override
    public List<RoleAuthorityTreeResp> roleAuthorityTree(Long roleId) {
        //最终返回的对象
        List<RoleAuthorityTreeResp> allTreeResp = new ArrayList<>();

        Long merchantId = WebFrameworkUtils.getMerchantId();

        //得到该商家的所有的菜单以及角色id还原是否有权限
        List<ModuleAuthorityResp> allModule=this.adminMenuService.getByAdminMenuList(merchantId,roleId);

        //得到二级节点的数据  Map<Long[父级节点],  List< ModuleAuthorityResp> 节点信息>
        Map<Long, List<RoleAuthorityTreeResp>> childMap = allModule.stream()
                .map(p-> new RoleAuthorityTreeResp(p))
                .filter(p -> !(p.getPid().equals(0L)))
                .collect(Collectors.groupingBy(RoleAuthorityTreeResp::getPid));

        //遍历一级节点
        allModule.stream().filter(p->p.getPid().equals(0L)).forEach(p-> {
            RoleAuthorityTreeResp  parent=new RoleAuthorityTreeResp(p);
            //父节点下在的子节点
            parent.setSonModule( childMap.get(parent.getModuleId()));
            //父节点是否选 （所有的子节点都必须要选中）
            boolean result=parent.getSonModule().stream().allMatch(s->s.getMark());
            parent.setMark(result);
            allTreeResp.add(parent);
        });
       return allTreeResp;
    }

    /**
     * 什么时候开启分布式事务 @GlobalTransactional  (该方法有多少个表参与 insert,update,delete操作)
     * @param req
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean add(AdminRoleAddReq req) {
        //判断商家表角色名称的唯一性
        Long merchantId = WebFrameworkUtils.getMerchantId();
        //判断角色名称唯一性
        LambdaQueryWrapper<AdminRole>  queryWrapper=new LambdaQueryWrapper<>();
        queryWrapper.eq(AdminRole::getRoleName,req.getRoleName());
        queryWrapper.eq(AdminRole::getMerchantId,merchantId);
        long count=this.count(queryWrapper);
        if(count>0){
            throw new ApiException(500,req.getRoleName()+",角色名称已存在");
        }

        //转换
        AdminRole  adminRole= AdminMapStruct.INSTANCE.convert(req);
        adminRole.setRoot(false);
        adminRole.setCreateTime(new Date());
        adminRole.setMerchantId(merchantId);

        return  this.save(adminRole);
    }

    /**
     * 编辑角色
     * @param req
     * @return
     */
    @Override
    public boolean editRole(AdminRoleEditReq req) {
        //判断商家表角色名称的唯一性
        Long merchantId = WebFrameworkUtils.getMerchantId();

        AdminRole db = findById(req.getRoleId());
        if(Objects.isNull(db)){
            throw new ApiException(ResultCode.DATA_NOT_FOUND);
        }

        //如果值不一样，判断角色名称唯一性
        if(!db.getRoleName().equals(req.getRoleName())){
            LambdaQueryWrapper<AdminRole>  queryWrapper=new LambdaQueryWrapper<>();
            queryWrapper.eq(AdminRole::getRoleName,req.getRoleName());
            queryWrapper.eq(AdminRole::getMerchantId,merchantId);
            queryWrapper.ne(AdminRole::getId,req.getRoleId());
            long count=this.count(queryWrapper);
            if(count>0){
                throw new ApiException(500,req.getRoleName()+",角色名称已存在");
            }
        }

        //转换
        AdminRole  adminRole= AdminMapStruct.INSTANCE.convert(req);
        adminRole.setRoot(db.getRoot());
        adminRole.setMerchantId(merchantId);
        adminRole.setUpdateTime(new Date());
        return this.updateById(adminRole);
    }

    /**
     * 修改角色权限
     * @param req
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean changeRoleAuthority(ChangeRoleAuthorityReq req) {
        Long merchantId = WebFrameworkUtils.getMerchantId();
        Long roleId = req.getRoleId();

        AdminRole adminRole = findById(req.getRoleId());

        if (adminRole.getRoot()) {
            throw new ApiException(500, "不能修改初始化角色的权限树");
        }

        //根据角色id删除模块权限
        this.adminRoleInnerModuleService.deleteModuleByRoleId(roleId,merchantId);
        //重新插入角色模块信息
        if(req.getModuleIds()!=null && req.getModuleIds().size()>0){
            List<AdminRoleInnerModule> list=new ArrayList<>();
            req.getModuleIds().forEach(c -> {
                AdminRoleInnerModule roleInnerModule = new AdminRoleInnerModule();
                roleInnerModule.setRoleId(roleId);
                roleInnerModule.setModuleId(c);
                roleInnerModule.setMerchantId(merchantId);
                list.add(roleInnerModule);
            });
            this.adminRoleInnerModuleService.saveBatch(list);
        }

        //清空redis 商户拥有角色id账户的缓存数据
        //RedisConstant.AUTHORIZATION + AuthConstant.ADMIN_CLIENT_ID + ":" + parameters.get("username")+merchantId;
        removeRedisCache(roleId);

        return true;
    }

    /**
     * 修改角色状态
     * @param req
     * @return
     */
    @Override
    public boolean changeRoleState(ChangeRoleStateReq req) {
        AdminRole db = findById(req.getRoleId());
        if (db.getRoot()) {
            throw new ApiException(500, "不能修改初始化角色的权限树");
        }

        db.setState(!db.getState());
        db.setUpdateTime(new Date());
        return this.updateById(db);
    }

    /**
     * 删除角色信息
     * @param roleId
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean delRole(Long roleId) {
        Long merchantId = WebFrameworkUtils.getMerchantId();
        AdminRole db = this.findById(roleId);
        if (db.getRoot()) {
            throw new ApiException(500, "不能删除初始化角色");
        }
        //根据角色查询
        long count=this.adminRoleInnerModuleService.existsAccountInnerRoleByRoleId(roleId);
        if(count>0){
            throw new ApiException(500, "请先移除当前角色下的所有账号");
        }
        //删除该角色信息
        this.removeById(roleId);
        //清空与角色相关的登录用户的缓存数据
        removeRedisCache(roleId);
        this.adminRoleInnerModuleService.deleteModuleByRoleId(roleId,merchantId);
        return true;
    }

    /**
     * 清空redis缓存中与角色相关的数据
     * @param roleId
     */
    private void removeRedisCache(Long roleId){
        //清空redis 商户拥有角色id账户的缓存数据
        //RedisConstant.AUTHORIZATION + AuthConstant.ADMIN_CLIENT_ID + ":" + parameters.get("username")+merchantId;
        List<AdminAccountResp> accountRespList = this.adminAccountService.findByRoleId(roleId);
        if (!CollUtil.isEmpty(accountRespList)) {
            //异步进行操作
            CompletableFuture.runAsync(new Runnable() {
                @Override
                public void run() {
                    List<String> collect=new ArrayList<>(accountRespList.size());
                    accountRespList.forEach(c -> {
                        String key = RedisConstant.AUTHORIZATION + AuthConstant.ADMIN_CLIENT_ID + ":" + c.getAccount() + c.getMerchantId();
                        collect.add(key);
                    });
                    //批量删除
                    redisTemplate.delete(collect);
                }
            });
        }

    }

    /**
     * 根据id查询数据
     * @param roleId
     * @return
     */
    private AdminRole findById(Long roleId){
        Long merchantId = WebFrameworkUtils.getMerchantId();

        LambdaQueryWrapper<AdminRole> queryWrapper=new LambdaQueryWrapper<>();
        queryWrapper.eq(AdminRole::getMerchantId,merchantId);
        queryWrapper.eq(AdminRole::getId,roleId);
        AdminRole adminRole = this.getOne(queryWrapper);
        if(Objects.isNull(adminRole)){
            throw new ApiException(500, "角色不存在");
        }
        return adminRole;
    }

}




